import { CdkDragDrop, CdkDragStart } from '@angular/cdk/drag-drop';
import { ElementRef, EventEmitter, inject } from '@angular/core';

import { ResizeEvent } from 'angular-resizable-element';
import { NzSafeAny } from 'ng-zorro-antd/core/types';

import { LayoutPosition, WidgetConfig } from './widget-default-setting';

export class DashboardWidget {
  isResize: boolean = false;
  leftPanelWidth: number = 340;
  resizeWidgetEvent!: EventEmitter<NzSafeAny>;
  private _rightContainer!: HTMLElement;

  get widget(): WidgetConfig | null {
    return this.getWidget();
  }

  get rightContainer(): HTMLElement {
    if (!this._rightContainer) {
      // get top parent element -- right design container
      this._rightContainer = document.querySelector(`#${this.widget!.tag}`)!.parentElement!.parentElement!.parentElement!;
    }

    return this._rightContainer;
  }

  getWidget(): WidgetConfig | null {
    return null;
  }

  onResizeStart(event: ResizeEvent): void {
    this.isResize = true;
  }

  onResizeEnd(event: ResizeEvent): void {
    this.updateWidgetLayoutPosition(event);
    this.isResize = false;
  }

  getWidgetProperty(propertyName: string): string {
    if (this.widget) {
      return this.widget[propertyName]!;
    }

    return '';
  }

  updateWidgetLayoutPosition(event: ResizeEvent): void {
    const { edges } = event;
    const { left, right, top, bottom } = edges;
    if (this.widget!.layout) {
      // header height
      const headerHeight = document.querySelector('.app-header')?.clientHeight ?? 0;
      if (left) {
        this.widget!.layout.left = this.toPercentage((event.rectangle.left - this.leftPanelWidth) / this.rightContainer.clientWidth);
      }

      if (top) {
        this.widget!.layout.top = this.toPercentage((event.rectangle.top - headerHeight) / this.rightContainer.parentElement!.clientHeight);
      }

      if (top || bottom) {
        this.widget!.layout.height = this.toPercentage(event.rectangle.height! / this.rightContainer.clientHeight);
      }

      if (left || right) {
        this.widget!.layout.width = this.toPercentage(event.rectangle.width! / this.rightContainer.clientWidth);
      }
      this.resizeWidgetEvent.emit({ layout: this.widget!.layout, tag: this.widget!.tag });
    }
  }

  dragStarted(event: CdkDragStart<WidgetConfig>): void {
    if (this.isResize) {
      event.event.preventDefault();
      return;
    }
  }

  toPercentage(num: number): string {
    return `${Number(100 * (num < 0 ? 0 : num)).toFixed(2)}%`;
  }

  checkAccept(element: HTMLElement): boolean {
    return element.classList.contains('inner-box');
  }

  setLayoutPositionForElement(element: HTMLElement): void {
    if (!this.widget!.layout) {
      return;
    }

    element.style.top = this.widget!.layout.top;
    element.style.left = this.widget!.layout.left;
  }

  getLeftPosition(event: CdkDragDrop<WidgetConfig[]>): string {
    const { x } = event.distance;
    let left = event.item.element.nativeElement.offsetLeft;
    const clientWidth = event.item.element.nativeElement.clientWidth;
    if (left + x + clientWidth > this.rightContainer.clientWidth) {
      left = this.rightContainer.clientWidth - clientWidth;
    } else {
      left = left + x;
    }

    if (left < 0 || left < 50) {
      left = 50;
    }

    return this.toPercentage(left / this.rightContainer.clientWidth);
  }

  getTopPosition(event: CdkDragDrop<WidgetConfig[]>): string {
    const { y } = event.distance;
    let top = event.item.element.nativeElement.offsetTop;
    const clientHeight = event.item.element.nativeElement.clientHeight;
    if (top + y + clientHeight > this.rightContainer.clientHeight) {
      top = this.rightContainer.clientHeight - clientHeight;
    } else {
      top = top + y;
    }

    if (top < 0 || top < 50) {
      top = 50;
    }

    return this.toPercentage(top / this.rightContainer.clientHeight);
  }

  dropWidget(event: CdkDragDrop<WidgetConfig[]>): void {
    this.setLayoutPositionForElement(event.item.element.nativeElement);
    if (this.isResize) {
      event.event.preventDefault();
      return;
    }

    // padding width
    const isTable = this.widget?.field === 'table';
    const width: number = event.item.element.nativeElement.clientWidth - (isTable ? 4 : 0);
    const height: number = event.item.element.nativeElement.clientHeight;
    const layout: LayoutPosition = {
      left: `${this.getLeftPosition(event)}`,
      top: `${this.getTopPosition(event)}`,
      width: `${width}`,
      height: `${height}`
    };

    this.widget!.layout = layout;
  }
}
